{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# En<->Fr translation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n",
      "/home/jhoward/anaconda3/lib/python3.6/site-packages/sklearn/cross_validation.py:44: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.\n",
      "  \"This module will be removed in 0.20.\", DeprecationWarning)\n"
     ]
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "import importlib\n",
    "import utils2; importlib.reload(utils2)\n",
    "from utils2 import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "from gensim.models import word2vec"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "limit_mem()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "path='/data/jhoward/datasets/fr-en-109-corpus/'\n",
    "dpath = 'data/translate/'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Prepare corpus"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "fname=path+'giga-fren.release2.fixed'\n",
    "en_fname = fname+'.en'\n",
    "fr_fname = fname+'.fr'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "re_eq = re.compile('^(Wh[^?.!]+\\?)')\n",
    "re_fq = re.compile('^([^?.!]+\\?)')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "lines = ((re_eq.search(eq), re_fq.search(fq)) \n",
    "         for eq, fq in zip(open(en_fname), open(fr_fname)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "ename": "KeyboardInterrupt",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m-----------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m               Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-8-bc0c2f49b326>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mqs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgroup\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgroup\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mf\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mlines\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0me\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      2\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mqs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m<ipython-input-8-bc0c2f49b326>\u001b[0m in \u001b[0;36m<listcomp>\u001b[0;34m(.0)\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mqs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgroup\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgroup\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mf\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mlines\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0me\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      2\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mqs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m<ipython-input-7-80a2f66f2a63>\u001b[0m in \u001b[0;36m<genexpr>\u001b[0;34m(.0)\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m lines = ((re_eq.search(eq), re_fq.search(fq)) \n\u001b[0m\u001b[1;32m      2\u001b[0m          for eq, fq in zip(open(en_fname), open(fr_fname)))\n",
      "\u001b[0;32m/home/jhoward/anaconda3/lib/python3.6/codecs.py\u001b[0m in \u001b[0;36mdecode\u001b[0;34m(self, input, final)\u001b[0m\n\u001b[1;32m    319\u001b[0m         \u001b[0;31m# decode input (taking the buffer into account)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    320\u001b[0m         \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbuffer\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 321\u001b[0;31m         \u001b[0;34m(\u001b[0m\u001b[0mresult\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mconsumed\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_buffer_decode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0merrors\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfinal\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    322\u001b[0m         \u001b[0;31m# keep undecoded input until the next call\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    323\u001b[0m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbuffer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mconsumed\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
     ]
    }
   ],
   "source": [
    "qs = [(e.group(), f.group()) for e,f in lines if e and f]\n",
    "len(qs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[('What is light ?', 'Qu’est-ce que la lumière?'),\n",
       " ('Who are we?', 'Où sommes-nous?'),\n",
       " ('Where did we come from?', \"D'où venons-nous?\"),\n",
       " ('What would we do without it?', 'Que ferions-nous sans elle ?'),\n",
       " ('What is the absolute location (latitude and longitude) of Badger, Newfoundland and Labrador?',\n",
       "  'Quelle sont les coordonnées (latitude et longitude) de Badger, à Terre-Neuve-etLabrador?'),\n",
       " ('What is the major aboriginal group on Vancouver Island?',\n",
       "  'Quel est le groupe autochtone principal sur l’île de Vancouver?')]"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "qs[:6]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "dump(qs, dpath+'qs.pkl')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "qs = load(dpath+'qs.pkl')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "en_qs, fr_qs = zip(*qs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "re_mult_space = re.compile(r\"  *\")\n",
    "re_mw_punc = re.compile(r\"(\\w[’'])(\\w)\")\n",
    "re_punc = re.compile(\"([\\\"().,;:/_?!—])\")\n",
    "re_apos = re.compile(r\"(\\w)'s\\b\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "def simple_toks(sent):\n",
    "    sent = re_apos.sub(r\"\\1 's\", sent)\n",
    "    sent = re_mw_punc.sub(r\"\\1 \\2\", sent)\n",
    "    sent = re_punc.sub(r\" \\1 \", sent).replace('-', ' ')\n",
    "    sent = re_mult_space.sub(' ', sent)\n",
    "    return sent.lower().split()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[['qu’', 'est', 'ce', 'que', 'la', 'lumière', '?'],\n",
       " ['où', 'sommes', 'nous', '?'],\n",
       " [\"d'\", 'où', 'venons', 'nous', '?'],\n",
       " ['que', 'ferions', 'nous', 'sans', 'elle', '?']]"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fr_qtoks = list(map(simple_toks, fr_qs)); fr_qtoks[:4]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[['what', 'is', 'light', '?'],\n",
       " ['who', 'are', 'we', '?'],\n",
       " ['where', 'did', 'we', 'come', 'from', '?'],\n",
       " ['what', 'would', 'we', 'do', 'without', 'it', '?']]"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "en_qtoks = list(map(simple_toks, en_qs)); en_qtoks[:4]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['rachel', \"'s\", 'baby', 'is', 'cuter', 'than', 'other', \"'s\", '.']"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "simple_toks(\"Rachel's baby is cuter than other's.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "def toks2ids(sents):\n",
    "    voc_cnt = collections.Counter(t for sent in sents for t in sent)\n",
    "    vocab = sorted(voc_cnt, key=voc_cnt.get, reverse=True)\n",
    "    vocab.insert(0, \"<PAD>\")\n",
    "    w2id = {w:i for i,w in enumerate(vocab)}\n",
    "    ids = [[w2id[t] for t in sent] for sent in sents]\n",
    "    return ids, vocab, w2id, voc_cnt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(19548, 26708)"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fr_ids, fr_vocab, fr_w2id, fr_counts = toks2ids(fr_qtoks)\n",
    "en_ids, en_vocab, en_w2id, en_counts = toks2ids(en_qtoks)\n",
    "len(en_vocab), len(fr_vocab)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Word vectors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "en_vecs, en_wv_word, en_wv_idx = load_glove(\n",
    "    '/data/jhoward/datasets/nlp/glove/results/6B.100d')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "en_w2v = {w: en_vecs[en_wv_idx[w]] for w in en_wv_word}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "n_en_vec, dim_en_vec = en_vecs.shape\n",
    "dim_fr_vec = 200"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "fr_wik = pickle.load(open('/data/jhoward/datasets/nlp/polyglot-fr.pkl', 'rb'), \n",
    "                     encoding='latin1')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "source": [
    "- Word vectors: http://fauconnier.github.io/index.html#wordembeddingmodels\n",
    "- Corpus: https://www.sketchengine.co.uk/frwac-corpus/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "w2v_path='/data/jhoward/datasets/nlp/frWac_non_lem_no_postag_no_phrase_200_skip_cut100.bin'\n",
    "fr_model = word2vec.KeyedVectors.load_word2vec_format(w2v_path, binary=True)\n",
    "fr_voc = fr_model.vocab"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "def create_emb(w2v, targ_vocab, dim_vec):\n",
    "    vocab_size = len(targ_vocab)\n",
    "    emb = np.zeros((vocab_size, dim_vec))\n",
    "\n",
    "    for i, word in enumerate(targ_vocab):\n",
    "        try:\n",
    "            emb[i] = w2v[word]\n",
    "        except KeyError:\n",
    "            # If we can't find the word, randomly initialize\n",
    "            emb[i] = normal(scale=0.6, size=(dim_vec,))\n",
    "\n",
    "    return emb"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(19548, 100)"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "en_embs = create_emb(en_w2v, en_vocab, dim_en_vec); en_embs.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(26708, 200)"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fr_embs = create_emb(fr_model, fr_vocab, dim_fr_vec); fr_embs.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Prep data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "en_lengths = collections.Counter(len(s) for s in en_ids)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "maxlen = 30"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1726, 50605)"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(list(filter(lambda x: len(x) > maxlen, en_ids))), len(\n",
    "    list(filter(lambda x: len(x) <= maxlen, en_ids)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(3579, 48752)"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(list(filter(lambda x: len(x) > maxlen, fr_ids))), len(\n",
    "    list(filter(lambda x: len(x) <= maxlen, fr_ids)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "en_padded = pad_sequences(en_ids, maxlen, padding=\"post\", truncating=\"post\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "fr_padded = pad_sequences(fr_ids, maxlen, padding=\"post\", truncating=\"post\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((52331, 30), (52331, 30), (19548, 100))"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "en_padded.shape, fr_padded.shape, en_embs.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "n = int(len(en_ids)*0.9)\n",
    "idxs = np.random.permutation(len(en_ids))\n",
    "fr_train, fr_test = fr_padded[idxs][:n], fr_padded[idxs][n:]\n",
    "en_train, en_test = en_padded[idxs][:n], en_padded[idxs][n:]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(47097, 30)"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "en_train.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "parms = {'verbose': 0, 'callbacks': [TQDMNotebookCallback()]}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 249,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "fr_wgts = [fr_embs.T, np.zeros((len(fr_vocab,)))]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 250,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "inp = Input((maxlen,))\n",
    "x = Embedding(len(en_vocab), dim_en_vec, input_length=maxlen,\n",
    "              weights=[en_embs], trainable=False)(inp)\n",
    "x = Bidirectional(LSTM(128, return_sequences=True))(x)\n",
    "x = Bidirectional(LSTM(128, return_sequences=True))(x)\n",
    "x = LSTM(128, return_sequences=True)(x)\n",
    "x = TimeDistributed(Dense(dim_fr_vec))(x)\n",
    "x = TimeDistributed(Dense(len(fr_vocab), weights=fr_wgts))(x)\n",
    "x = Activation('softmax')(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 251,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "model = Model(inp, x)\n",
    "model.compile('adam', 'sparse_categorical_crossentropy')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 253,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "K.set_value(model.optimizer.lr, 1e-3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 255,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "hist=model.fit(en_train, np.expand_dims(fr_train,-1), batch_size=64, nb_epoch=20, **parms, \n",
    "               validation_data=[en_test, np.expand_dims(fr_test,-1)])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 264,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true,
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\nf7GvkNGckJ2GAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7fd938e8cc50>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_train(hist)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 154,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "model.save_weights(dpath+'trans.h5')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 157,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "model.load_weights(dpath+'trans.h5')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Testing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 205,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "def sent2ids(sent):\n",
    "    sent = simple_toks(sent)\n",
    "    ids = [en_w2id[t] for t in sent]\n",
    "    return pad_sequences([ids], maxlen, padding=\"post\", truncating=\"post\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 208,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "def en2fr(sent): \n",
    "    ids = sent2ids(sent)\n",
    "    tr_ids = np.argmax(model.predict(ids), axis=-1)\n",
    "    return ' '.join(fr_vocab[i] for i in tr_ids[0] if i>0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 212,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'quelle est le nombre du canada ?'"
      ]
     },
     "execution_count": 212,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "en2fr(\"what is the size of canada?\")"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python [conda root]",
   "language": "python",
   "name": "conda-root-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
